/**$Licence:
 *   Use this however/wherever you like, just don't blame me if it breaks anything.
 *   Copyright (C) 2008 - 2013 xingsheng.zhu@gmail.com All rights reserved.
 */
package com.blazemina.config.annotation;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.blazegame.logging.Logger;
import com.blazegame.logging.LoggerFactory;
import com.blazemina.CommandContext;
import com.blazemina.command.Command;
import com.blazemina.command.CommandFactory;
import com.blazemina.config.BlazeminaConfigManager;
import com.blazemina.config.CommandMappingConfig;
import com.blazemina.config.entities.CommandConfig;
import com.blazemina.util.ClassUtils;

/**
 * @author JackChu
 * @version 2.0.0 2013-2-21 下午5:12:43
 */
public class AnnotationCommandConfig implements CommandMappingConfig {
	
	private final static Logger logger = LoggerFactory.getLogger(AnnotationCommandConfig.class);

	public Map<String, CommandConfig> buildCommandMapping() {
		Map<String, CommandConfig> commandConfigs = new HashMap<String, CommandConfig>();

		Map<String, Boolean> commandPackages = BlazeminaConfigManager.me()
				.getCommandPackages();

		for (Entry<String, Boolean> entry : commandPackages.entrySet()) {
			String pack = entry.getKey();
			boolean recursive = entry.getValue();
			Set<Class<?>> classes = ClassUtils.findClasses(pack, recursive);
			for (Class<?> clazz : classes) {
				Method[] methods = clazz.getMethods();
				for (Method method : methods) {
					CommandMapping commandMapping = (CommandMapping) method
							.getAnnotation(CommandMapping.class);
					if (commandMapping != null) {

						Class<?>[] parameterTypes = method.getParameterTypes();
						if (parameterTypes != null
								&& parameterTypes.length == 1
								&& parameterTypes[0]
										.equals(CommandContext.class)) {
							String command = commandMapping.command();
							CommandConfig commandConfig = new CommandConfig();
							commandConfig.setCommand(command);
							commandConfig.setMethod(method);
							Command commandObject = createCommand(clazz);
							commandConfig.setCommandObject(commandObject);
							commandConfigs.put(command, commandConfig);
							if(logger.isDebugEnabled()){
								logger.debug("config action mapping,cmd:"+command+",commandObject:"+clazz.getName()+",method:"+method.getName());
							}
						}
					}
				}
			}
		}
		return commandConfigs;
	}

	private Command createCommand(Class<?> clazz) {
		CommandFactory commandFactory = BlazeminaConfigManager.me()
				.getCommandFactory();
		return (Command) commandFactory.lookup(clazz);
	}

}
